package com.company.network.base;

import com.company.network.cominterceptor.ComReqInterceptor;
import com.company.network.cominterceptor.ComRespInterceptor;
import com.company.network.enviroment.EnvironmentActivity;
import com.company.network.enviroment.IEnvironment;
import com.company.network.errorhandler.HttpErrorHandler;
import com.company.network.logger.HttpLogger;
import com.rxjava.rxlife.RxLife;
import com.rxjava.rxlife.Scope;

import java.util.HashMap;

import io.reactivex.Observable;
import io.reactivex.ObservableTransformer;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

public abstract class NetWorkApi implements IEnvironment {

    private String mBaseUrl;

    private static final String TAG = "NetWorkApi";

    private static INetWorkRequestInfo netWorkRequestInfo;

    private static HashMap<String, Retrofit> retrofitHashMap = new HashMap<>();

    private static boolean mIsFormal = true;


    protected NetWorkApi() {
        if (!mIsFormal) {
            this.mBaseUrl = getTest();
            return;
        }
        mBaseUrl = getFormal();
    }

    public static void init(INetWorkRequestInfo requestInfo) {
        netWorkRequestInfo = requestInfo;
        mIsFormal = EnvironmentActivity.isOfficialEnvironment(requestInfo.getApplicationContext());
    }

    protected Retrofit getRetrofit(Class service) {
        if (retrofitHashMap.get(mBaseUrl + service.getName()) != null) {
            return retrofitHashMap.get(mBaseUrl + service.getName());
        }
        Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
        retrofitBuilder.baseUrl(mBaseUrl);
        retrofitBuilder.addConverterFactory(GsonConverterFactory.create());
        retrofitBuilder.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
        retrofitBuilder.client(getOkHttpClient());
        Retrofit retrofit = retrofitBuilder.build();
        retrofitHashMap.put(mBaseUrl + service.getName(), retrofit);
        return retrofit;
    }

    private OkHttpClient getOkHttpClient() {
        OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
        if (getInterceptor() != null) {
            okHttpClientBuilder.addInterceptor(getInterceptor());
        }
        okHttpClientBuilder.addInterceptor(new ComReqInterceptor(netWorkRequestInfo));
        okHttpClientBuilder.addInterceptor(new ComRespInterceptor());
        if (netWorkRequestInfo != null && netWorkRequestInfo.isDebug()) {
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLogger());
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            okHttpClientBuilder.addNetworkInterceptor(loggingInterceptor);
        }

        return okHttpClientBuilder.build();
    }

    public <T> ObservableTransformer<T, T> applySchedulers(Observer<T> observer, Scope scope) {
        return upstream -> {
            Observable<T> observable = upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .map(getAppErrorHandler())
                    .onErrorResumeNext(new HttpErrorHandler<T>());
            observable.as(RxLife.as(scope)).subscribe(observer);
            return observable;
        };
    }


    protected abstract Interceptor getInterceptor();

    protected abstract <T> Function<T, T> getAppErrorHandler();

}
